/*
 *   This file is part of ed_pvr.
 *
 *   ed_pvr is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 2 of the License, or
 *   (at your option) any later version.
 *
 *   ed_pvr is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with ed_pvr.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <inttypes.h>
#include <fcntl.h>
#include <unistd.h>
#include <memory.h>
#include <getopt.h>
#include <pthread.h>
#include <errno.h>
#include <signal.h>
#include <ctype.h>
#include "device.h"
#include "utils.h"
#include "tuner_hdhr.h"
#include "mpegts_io.h"
//#include "fastmemcpy.h"

#define HDHR_MAX_DEV_COUNT					64
#define HDHR_DEFAULT_READ_SZ				(20 * 1316)
#define HDHR_DEFAULT_BINDIP					"0.0.0.0"
#define HDHR_DEFAULT_BINDPORT				8988

#define HDHR_DEFAULT_CHANNELS_CONF			"channels.conf"
#define CHANNELS_CONF_ID_ATSC				"B8M10"

// Callback(s) for device

uint8_t hdhr_read_data(TUNER_STRUCT *);
int hdhr_tune_channel(TUNER_STRUCT *, TUNER_INITPASS_STRUCT*);
uint8_t hdhr_update_stats(TUNER_STRUCT *);

// Internal functions, shouldn't be called from outside

int _hdhr_get_channel_lineup(TUNER_HDHR_STRUCT *);
int _hdhr_channel_change(TUNER_STRUCT *, TUNER_CHANNEL_STRUCT *);
uint8_t hdhr_destroy(TUNER_STRUCT *);
int _hdhrdev_vprintw(DEVICE_STRUCT *, const char *, va_list);

/* HDHR Specific for tuning/changing channels */
int _hdhr_channel_change(TUNER_STRUCT *tuner, TUNER_CHANNEL_STRUCT *chan_struct)
{
//	printf("_hdhr_channel_change start\n");
	if (tuner && tuner->extra_data[0] && chan_struct && chan_struct->pid_count)
	{
		DEVICE_STRUCT *device = tuner->parent;
		TUNER_HDHR_STRUCT *hdhr_device = device->parent;
		char * tunername_copy = strdup(tuner->name);

		if (tunername_copy)
		{
			int64_t now=0, start=0;
			int prog_num = 0;
			int i, k, j, found;
			char *split[3] = {0};
			char hdhr_cmd_str[MAX_DEVNAME_SIZE] = {0};
			char hdhr_var_str[MAX_DEVNAME_SIZE] = {0};
//			char hdhr_var_tmp[MAX_DEVNAME_SIZE] = {0};
			char *ret_error = NULL, *ret_value = NULL;
			char *status = NULL;
			struct hdhomerun_device_t *hdhr_obj = (struct hdhomerun_device_t*)tuner->extra_data[0];

			split[0] = strtok(tunername_copy, " ");
			split[1] = strtok(NULL, " ");

			sprintf(hdhr_cmd_str, "%schannel", split[1]);
			sprintf(hdhr_var_str, "auto:%" PRId64, chan_struct->program_num);

//			printf("1: %s -- %s\n", hdhr_cmd_str, hdhr_var_str);
			if (hdhomerun_device_set_var(hdhr_obj, hdhr_cmd_str, hdhr_var_str, NULL, &ret_error) < 0)
			{
				utils_log_print(hdhr_device->device->log, "[HDHR] Problem Setting Frequency\n");
				return -1;
			}

			start = (int64_t)time(NULL);
			while (1)
			{
				sprintf(hdhr_cmd_str, "%sstatus", split[1]);
				now = (int64_t)time(NULL);
				if (now - start > 4)
				{
					printf("[HDHR] HDHR -- unable to tune\n");
					return -1;
				}

				if (hdhomerun_device_get_var(hdhr_obj, hdhr_cmd_str, &ret_value, &ret_error) < 0)
				{
					utils_log_print(hdhr_device->device->log, "[HDHR] HDHR -- unable to get status\n");
					return -1;
				}
//				printf("---- %s\n", ret_value);

				status = strtok(ret_value, " ");
				status = strtok(NULL, " ");

				if (status[5] == 'n' && status[5] == 'o' && status[6] == 'n' && status[7] == 'e')
				{
					usleep(1000 * 500);
					continue;
				}

				status = strtok(NULL, " ");
				status = strtok(NULL, " ");
				status = strtok(NULL, " ");
				status = strtok(NULL, " ");
//				printf("HMM: %s (%s) -- %c\n", ret_value, status, status[4]);

				if (status[4] == '0')
					usleep(1000 * 500);
				else
					break;

			}

			sprintf(hdhr_cmd_str, "%sstreaminfo", split[1]);
//			printf("MOO2: %s\n", hdhr_cmd_str);

//			printf("3: %s\n", hdhr_cmd_str);

			if (hdhomerun_device_get_var(hdhr_obj, hdhr_cmd_str, &ret_value, &ret_error) < 0)
			{
				utils_log_print(hdhr_device->device->log, "[HDHR] HDHR -- unable to get streaminfo\n");
				return -1;
			}

//			printf("HMM: %s\n", ret_value);

			j = k = i = found = 0;
			memset(hdhr_var_str, 0, MAX_DEVNAME_SIZE);

			while (ret_value[i] != '\0')
			{
				hdhr_var_str[k] = ret_value[i];
				if (hdhr_var_str[k] == 0xa)
				{
					j++;
					hdhr_var_str[k] = '\0';

					if (isdigit(hdhr_var_str[0]))
					{
						if (strstr(hdhr_var_str, chan_struct->info))
						{
							char *tmp = strdup(hdhr_var_str);
							if (tmp)
							{
								int i;
								for(i=0; i < strlen(tmp); i++)
								{
									if (tmp[i] == ':')
									{
										tmp[i] = '\0';
										chan_struct->pgm_pmt = prog_num = atoi(tmp);
										break;
									}
								}
								free(tmp);
							}
							found = 1;
							break;
						}
					}

					k = 0;
					memset(hdhr_var_str, 0, MAX_DEVNAME_SIZE);
				}
				else
				{
					k++;
				}
//				printf("%c (0x%x)\n", ret_value[i], ret_value[i]);
				i++;
			}

			if (found)
			{
				sprintf(hdhr_cmd_str, "%sprogram %d", split[1], prog_num);
//				printf("M [%d]: %s\n", prog_num, hdhr_cmd_str);
				if (hdhomerun_device_set_var(hdhr_obj, hdhr_cmd_str, chan_struct->info, NULL, &ret_error) < 0)
				{
					utils_log_print(hdhr_device->device->log, "[HDHR] HDHR -- unable to set program\n");
					return -1;
				}
			}
			else
			{
//				utils_log_print(hdhr_device->device->log, "Bleah\n");
				return -1;
			}

			if (hdhomerun_device_stream_start(hdhr_obj) <= 0)
			{
				utils_log_print(hdhr_device->device->log, "[HDHR] HDHR -- unable to start stream\n");
				return -1;
			}

			hdhomerun_device_stream_flush(hdhr_obj);

			utils_log_print(hdhr_device->device->log, "[HDHR] HDHR (%s) Tuned [Freq: %" PRId64"]  [Stream Info: %s -- %s]\n", split[1], chan_struct->program_num, hdhr_var_str, chan_struct->info);
			free(tunername_copy);
		}
	}
//	printf("_hdhr_channel_change end\n");
	return 0;
}


int _hdhr_get_channel_lineup(TUNER_HDHR_STRUCT *dev)
{
	int filehandle = -1;
	char *tmp_mem = NULL;
	off_t sz = 0;

	if (!dev)
	{
	 	utils_log_print(dev->device->log,"[HDHR] _hdhr_get_channel_lineup: device is null\n");
		return 1;
	}

	filehandle = open(dev->channels_file, O_RDONLY);

	if (filehandle == -1)
	{
	 	utils_log_print(dev->device->log, "[HDHR] Can't open HDHR channel config\n");
		return 1;
	}

	sz = get_file_size(dev->channels_file);
	tmp_mem = calloc(1, sz);

	if (tmp_mem)
	{
		int bytes_read = 0;
		TEXTFILE_IN_MEMORY *memf = NULL;
		char * line = NULL;

		lseek(filehandle, 0, SEEK_SET);
		bytes_read = get_bytes_from_file(filehandle, (uint8_t *)tmp_mem, sz);

		if (bytes_read != sz)
		{
			utils_log_print(dev->device->log, "READ ERRORORORORO: %d\n", bytes_read);
			return 0;
		}

		memf = memfile_init((char*)tmp_mem, (int)bytes_read);
		if (memf)
		{
			int p;
			int line_count = memfile_getline_count(memf);
			char *channels[15] = {0};
			uint32_t last_channel = 0;
			utils_log_print(dev->device->log,  "[HDHR] Parsing Channels from: %s.. ", dev->channels_file);

			for (p=0; p < line_count; p++)
			{
				line = memfile_getnext_line(memf, 1);
				if (line && line[0] == ':' && line[1] == '@')
				{
					last_channel = atoi(line+2);
					continue;
				}

				if (line)
				{
					char *_tmpline = strdup(line);
					if (_tmpline)
					{
						uint64_t tmpnum1 = 0;
						char tmpstr[1024] = {0}, tmpstr2[1024] = {0};
//						printf("LINE: %s\n", _tmpline);

						channels[0] = strtok(_tmpline, ":");
						channels[1] = strtok(NULL, ":");
						channels[2] = strtok(NULL, ":");
						channels[3] = strtok(NULL, ":");
						channels[4] = strtok(NULL, ":");
						channels[5] = strtok(NULL, ":");
						channels[6] = strtok(NULL, ":");
						channels[7] = strtok(NULL, ":");
						channels[8] = strtok(NULL, ":");
						channels[9] = strtok(NULL, ":");
						channels[10] = strtok(NULL, ":");
						channels[11] = strtok(NULL, ":");
						channels[12] = strtok(NULL, ":");
						channels[13] = strtok(NULL, ":");
						channels[14] = strtok(NULL, ":");

						if (memcmp(channels[2], CHANNELS_CONF_ID_ATSC, strlen(CHANNELS_CONF_ID_ATSC)) == 0)
						{
							int k,q;
							char *tok = NULL, *last=NULL;

							strcpy(tmpstr, channels[1]);

							for (k=5; k <= 6; k++)
								for (q=0; q < strlen(channels[k]); q++)
									if (channels[k][q] == ';')
										channels[k] = &channels[k][q+1];

							tok = strtok(channels[5], "=");
							while (tok)
							{
								last = tok;
								tok = strtok(NULL, "=");
								if (tok)
								{
//									printf("VPID: %s\n", last);
									strcat(tmpstr, last);
									strcat(tmpstr2, last);
									strcat(tmpstr2, ",");
								}
							}

							tok = strtok(channels[6], ",");
							while (tok)
							{
								if (tok)
								{
									uint8_t do_filter = 0;
									last = strdup(tok);
									if (last)
									{
//										printf("HERE: %s\n", last);
										for(k=1; k < strlen(last); k++)
										{
											if (last[k] == '=')
											{
												if (last[k+1] == 'e' && last[k+2] == 's' && last[k+3] == 'l')
												{
//													do_filter = 1;
//													printf("FILTERING\n");
												}
												last[k] = '\0';
												break;
											}
										}
										if (do_filter == 0)
										{
//											printf("APID: %s\n", last);
											strcat(tmpstr, last);
											strcat(tmpstr2, last);
											strcat(tmpstr2, ",");
										}
										free(last);
									}
								}
								tok = strtok(NULL, ",");
							}

//							printf("ChName: %s, %s, %s -- %s %s\n", channels[0], channels[1], channels[2], channels[3], channels[12]);

							//tmpnum = strtol(tmpstr, (char **)NULL, 10);
							tmpnum1 = strtol(channels[1], (char **)NULL, 10);

							device_channel_add(dev->device, last_channel, tmpnum1);
							tok = strtok(tmpstr2, ",");
							while (tok)
							{
								if (tok)
								{
									device_channel_add_pid(dev->device, last_channel, tmpnum1, atoi(tok), 0);
								}
								tok = strtok(NULL, ",");
							}
							device_channel_add_name(dev->device, last_channel, tmpnum1, channels[0]);
							device_channel_add_info(dev->device, last_channel, tmpnum1, channels[12]);
						}
						free(_tmpline);
					}
				}
			}
			utils_log_print(dev->device->log,  " Done\n");

			free(memf);
		}

		free(tmp_mem);
	}

	return 0;
}


/* End of HDHR Specific Stuff */



MPEGTS_PAT_PROGRAM_STRUCT * _hdhr_process_pat(MPEGTS_PAT * pat, TUNER_CHANNEL_STRUCT * tuner_chan)
{
	if (pat && pat->first_program && tuner_chan)
	{
		MPEGTS_PAT_PROGRAM_STRUCT *pgm =  pat->first_program;
		MPEGTS_PAT_PROGRAM_STRUCT * n = malloc(sizeof(MPEGTS_PAT_PROGRAM_STRUCT));
		while(pgm)
		{
			if (pgm->program_number && tuner_chan->pgm_pmt == pgm->program_number)
			{
				break;
			}
			pgm = pgm->next;
		}

		if (pgm)
		{
			memcpy(n, pgm, sizeof(MPEGTS_PAT_PROGRAM_STRUCT));
		}
		else
		{
			free(n);
			n = NULL;
		}
		return n;
	}
	return NULL;
}


int hdhr_tune_channel(TUNER_STRUCT *tuner,TUNER_INITPASS_STRUCT *tpass)
{
//	printf("hdhr_tune_channel Start: %d\n", chan);
	DEVICE_STRUCT *dev = (DEVICE_STRUCT *)tuner->parent;
//	TUNER_HDHR_STRUCT *hdhr_device = NULL;

	if (tuner && tuner->parent && tpass)
	{
		uint32_t chan = tpass->channel_num;
		TUNER_CHANNEL_STRUCT * tchan = NULL;
//		hdhr_device = dev->parent;

		if (dev)
		{
			tchan = device_channel_get_struct(dev, chan, 0);
			if (tchan)
			{
				if (_hdhr_channel_change(tuner, tchan) == -1)
					return TUNER_TUNE_ERROR_UNKNOWN;
			}
			else
				return TUNER_TUNE_ERROR_NOCHAN;
		}
	}
	else
	{
//		utils_log_print(hdhr_device->device->log, "hdhr_tune_channel NOOOOOO\n");
	}

//	printf("hdhr_tune_channel end2\n");
	return 0;
}

uint8_t hdhr_close_data(TUNER_STRUCT * tuner)
{
	uint8_t ret = 1;
	if (tuner && tuner->extra_data[0])
	{
		DEVICE_STRUCT *device = tuner->parent;
		TUNER_HDHR_STRUCT *hdhr_device = device->parent;
		struct hdhomerun_device_t *hdhr_obj = (struct hdhomerun_device_t*)tuner->extra_data[0];

		utils_log_print(hdhr_device->device->log,"[HDHR] Stopping & Flushing tuner: %s\n", tuner->name);
		hdhomerun_device_stream_stop(hdhr_obj);
		hdhomerun_device_stream_flush(hdhr_obj);
	}
	return ret;
}


uint8_t hdhr_destroy(TUNER_STRUCT * tuner)
{
	DEVICE_STRUCT *device = tuner->parent;
	TUNER_HDHR_STRUCT *hdhr_device = device->parent;
	TUNER_STRUCT * del = NULL;

	utils_log_print(hdhr_device->device->log,"[HDHR] Exiting, cleaning up...\n");

	while(tuner)
	{
		struct hdhomerun_device_t *hdhr_obj = tuner->extra_data[0];

		device_tuner_destroy(tuner);

//		printf("[HDHR] no more writing\n");

		if (hdhr_obj)
		{
			utils_log_print(hdhr_device->device->log,"[HDHR] destroying: %s\n", tuner->name);
			hdhomerun_device_stream_stop(hdhr_obj);
			hdhomerun_device_stream_flush(hdhr_obj);
			hdhomerun_device_destroy(hdhr_obj);
		}

		del = tuner;
		tuner = tuner->next;

		if (del)
		{
			mpegts_io_close(del->mpegts_io, 1);
//			free(del);
		}
	}
	device_destroy(device);
	utils_log_print(hdhr_device->device->log,"[HDHR] Clean up done!\n");

	return 0;
}

uint8_t hdhr_update_stats(TUNER_STRUCT *tuner)
{
	if (tuner && tuner->extra_data[0])
	{
		struct hdhomerun_device_t *hdhr_obj = (struct hdhomerun_device_t*)tuner->extra_data[0];
		struct hdhomerun_tuner_status_t status;
		if (hdhomerun_device_get_tuner_status(hdhr_obj, NULL, &status) > 0)
		{
			tuner->signal_strength = (status.signal_strength * 0xffff)/100;
			tuner->signal_noise_ratio = (status.signal_to_noise_quality * 0xffff)/100;
			return 1;
		}
	}
	printf("_hdhr_update_stats bad\n");
	return 0;
}
uint8_t hdhr_read_data(TUNER_STRUCT * tuner)
{
	uint8_t ret = 1;
	if (tuner && tuner->read_data_ptr && tuner->extra_data[0])
	{
		DEVICE_STRUCT *device = tuner->parent;
		TUNER_HDHR_STRUCT *hdhr_device = device->parent;

		struct hdhomerun_device_t *hdhr_obj = (struct hdhomerun_device_t*)tuner->extra_data[0];
		size_t bytes_read = 0, bytes_in = 0;
		size_t read_sz = tuner->read_size;
		uint8_t *ptr = NULL, _count = 0;

		ret = 0;

//		printf("HDHR read: %d\n", get_time_ms());
		while (bytes_in < tuner->read_size)
		{
			ptr = hdhomerun_device_stream_recv(hdhr_obj, read_sz, &bytes_read);

			if (ptr && (uint64_t)bytes_read > 0)
			{
				memcpy(tuner->read_data_ptr + bytes_in, ptr, bytes_read);
				bytes_in += bytes_read;
				read_sz -= bytes_read;
				_count = 0;
			}
			else
			{
				usleep(64 * 1000);

				if (_count++ > 80)
				{
					utils_log_print(hdhr_device->device->log,"[HDHR] no HDHR data, reseting: %d\n", _count);
					if (!ptr)
						utils_log_print(hdhr_device->device->log,"[HDHR] PTR NULL\n");
					if ((uint64_t)bytes_read <= 0)
						utils_log_print(hdhr_device->device->log,"[HDHR] BYTES READ BAD\n");

					ret = 1;
					break;
				}
				_count++;
			}
		}
//		usleep(32);
	}
	else
	{
//		utils_log_print(hdhr_device->device->log,"[HDHR] ceton_read_data error, something null\n");
	}
	return ret;
}

TUNER_HDHR_STRUCT * tuner_hdhr_init(DEVICE_INIT_ARGS_STRUCT *devopts)
{
	TUNER_HDHR_STRUCT * hdhrdev = NULL;

	if (devopts && devopts->device_name && devopts->channels_file && devopts->bind_ip && devopts->bind_port)
	{
		hdhrdev = calloc(1, sizeof(TUNER_HDHR_STRUCT));
		if (hdhrdev)
		{
			struct hdhomerun_discover_device_t result_list[HDHR_MAX_DEV_COUNT];
			int devices = 0, i = 0;
//			printf("[HDHR] Device and Tuner init: %s\n", devopts->device_name);
			for(i = 0; i < HDHR_MAX_DEV_COUNT; i++)
				memset(&result_list[i],  0, sizeof(struct hdhomerun_discover_device_t));

			hdhrdev->atsc_id = strdup(devopts->atsc_id);
			hdhrdev->hdhr_dev_str = strdup(devopts->device_name);
			hdhrdev->hdhr_dev_int = htoi(hdhrdev->hdhr_dev_str);
			hdhrdev->channels_file = strdup(devopts->channels_file);
			hdhrdev->device = device_init(devopts->bind_ip, devopts->bind_port);

			if (hdhrdev->device)
			{
				TUNER_STRUCT *tmptuner = NULL;
				struct hdhomerun_device_t *hdhr_obj;
				char tmpdev[MAX_DEVNAME_SIZE] = {0};


				hdhrdev->device->cb_dev_printf = generic_vprintw;

				hdhrdev->device->stream_only = 1;
				_hdhr_get_channel_lineup(hdhrdev);

				pthread_mutex_lock(&hdhrdev->device->tunerlock);
				hdhrdev->device->parent = (void *) hdhrdev;

				devices = hdhomerun_discover_find_devices_custom(0, HDHOMERUN_DEVICE_TYPE_TUNER, HDHOMERUN_DEVICE_ID_WILDCARD, result_list, HDHR_MAX_DEV_COUNT);

				for (i=0; i < devices; i++)
				{
					if (result_list[i].device_id == hdhrdev->hdhr_dev_int)
						hdhrdev->device->max_tuners += result_list[i].tuner_count;
				}

				for (i=0; i < hdhrdev->device->max_tuners; i++)
				{
					tmptuner = device_tuner_init(TUNE_TYPE_HDHR);

					if (tmptuner)
					{
						hdhr_obj = NULL;
						snprintf(tmpdev, MAX_DEVNAME_SIZE, "%s-%d/", hdhrdev->hdhr_dev_str, i);
						hdhr_obj = hdhomerun_device_create_from_str(tmpdev, NULL);

						if (hdhr_obj)
						{
							uint32_t device_id_requested = hdhomerun_device_get_device_id_requested(hdhr_obj);
							if (!hdhomerun_discover_validate_device_id(device_id_requested))
							{
								printf("[HDHR] hdhomerun_discover_validate_device_id failed, dev_id: %08lX\n", (unsigned long)device_id_requested);
								continue;
							}
							else
							{
								int count = 0;
								const char *model = hdhomerun_device_get_model_str(hdhr_obj);
								while (!model)
								{
									usleep(1000*1000);
									count++;
									model = hdhomerun_device_get_model_str(hdhr_obj);

									if (count > 4)
										break;
								}

								if (!model)
								{
									printf("[HDHR] hdhomerun_device_get_model_str failed\n");
									hdhomerun_device_destroy(hdhr_obj);
									continue;
								}

//								printf("[HDHR] [%d] Dev. Model: %s (count: %d)\n", i, model, count);
								snprintf(tmpdev, MAX_DEVNAME_SIZE, "%s /tuner%d/", hdhrdev->hdhr_dev_str, i);
								strncpy(tmptuner->name, tmpdev, strlen(tmpdev));

								tmptuner->segment_dir = devopts->segment_dir;
								tmptuner->base_filename = devopts->base_filename;

								tmptuner->mpegts_fileunit_maxsize = devopts->max_segment_size;
								tmptuner->mpegts_fileunit_maxlife = devopts->max_segment_life;

//								printf("[HDHR] File Segment Size: %d, Life (s): %d\n", tmptuner->mpegts_fileunit_maxsize, tmptuner->mpegts_fileunit_maxlife);
								tmptuner->read_thread_sleep_time = 64*1000;
								tmptuner->extra_data[0] = (void *) hdhr_obj;

								tmptuner->cb_read_data = hdhr_read_data;
								tmptuner->cb_close_data = hdhr_close_data;
								tmptuner->cb_tune_channel = hdhr_tune_channel;
								tmptuner->cb_update_tuner_stats = hdhr_update_stats;


								tmptuner->cb_process_pat =  _hdhr_process_pat;
//								tmptuner->packets_to_buffer = HDHR_DEFAULT_READ_SZ / 188;
								tmptuner->packets_to_buffer = 10;
								tmptuner->read_size = HDHR_DEFAULT_READ_SZ;
								tmptuner->parent = (void*) hdhrdev->device;

								tmptuner->cb_gui_tuner_read_status  = win_tuner_read_status;
								tmptuner->cb_gui_tuner_write_status  = win_tuner_write_status;

								tmptuner->id_offset = 1;
								tmptuner->id = i+1;

								device_tuner_add(hdhrdev->device, tmptuner);
								pthread_mutex_unlock(&tmptuner->init_mutex);
							}
						}
						else
						{
							printf("BLAAAAAAAAAA\n");
						}
					}
				}
				pthread_mutex_unlock(&hdhrdev->device->tunerlock);
			}
			else
			{
//				printf("I iz sad\n");
				pthread_mutex_unlock(&hdhrdev->init_mutex);
			}
		}
	}
	return hdhrdev;
}


#ifdef _MAIN_

uint8_t	use_curses = 1;
uint8_t sigint_h = 0;

TUNER_HDHR_STRUCT * hdhr_device = NULL;
DEVICE_INIT_ARGS_STRUCT _opts = {	.bind_ip = HDHR_DEFAULT_BINDIP,
									.bind_port = HDHR_DEFAULT_BINDPORT,
									.max_segment_size = MPEGTS_IO_MAX_SIZE_DEFAULT,
									.channels_file = HDHR_DEFAULT_CHANNELS_CONF,
									.device_name = NULL,
									.atsc_id = CHANNELS_CONF_ID_ATSC
								};

void display_usage(char *exe)
{
}


static const char *optString = "1:2:s:f:l:p:c:a:n?h";

static const struct option longOpts[] =
{
/*
	{ "listenip", required_argument, NULL, 'l' },
	{ "listenport", required_argument, NULL, 'p' },
	{ "tuners", required_argument, NULL, 'm' },
	{ "hdhrip", required_argument, NULL, 'c' },
	{ "hdhrport", required_argument, NULL, 'd' },
*/
	{ "help", no_argument, NULL, 'h' },
	{ NULL, no_argument, NULL, 0 }
};

uint8_t get_opts(int argc, char *const argv[], DEVICE_INIT_ARGS_STRUCT *devopts)
{
	int index = 0;
	int opt = getopt_long( argc, argv, optString, longOpts, &index );

	if (opt == -1 )
	{
		display_usage(argv[0]);
		return 1;
	}


	while ( opt != -1 )
	{
		switch ( opt )
		{
			case 'n':
				use_curses = !use_curses;
				break;
			case '1':
				devopts->max_segment_size = atoi(optarg);
				break;

			case '2':
				devopts->max_segment_life = atoi(optarg);
				break;

			case 'l':
				devopts->bind_ip = optarg;
				break;

			case 'p':
				devopts->bind_port = atoi(optarg);
				break;

			case 'c':
				devopts->channels_file = optarg;
				break;

			case 'a':
				devopts->device_name = optarg;
				break;

			case 's':
				devopts->segment_dir = optarg;
				break;

			case 'f':
				devopts->base_filename = optarg;
				break;

			case 'h':
			case '?':
				display_usage(argv[0]);
				break;

			default:
				break;
		}
		opt = getopt_long( argc, argv, optString, longOpts, &index );
	}
	return 0;
}

void sigint_handler()
{
	if (!sigint_h)
	{
		if (!use_curses)
		{
			pthread_mutex_unlock(&hdhr_device->init_mutex);
		}
		sigint_h = 1;
	}
}

void sigpipe_handler()
{
//   printf("SIGPIPE caught\n");
}

int main(int argc, char *argv[])
{
	signal(SIGPIPE,sigpipe_handler);
	signal(SIGINT,sigint_handler);

	get_opts(argc, argv, &_opts);
	_opts.max_segment_size = get_nearest_page_size(_opts.max_segment_size, TS_PACKET_SIZE);
	if (!_opts.device_name)
	{
		printf("[HDHR] No HDHR device name specified, exiting\n");
		return 1;
	}

	hdhr_device = tuner_hdhr_init(&_opts);

	if (hdhr_device && hdhr_device->device)
	{
		if (use_curses)
		{
			int loop = 1, ch;
//			win_init();
			hdhr_device->screen = edpvr_win_init(hdhr_device->device);

			while (loop && !sigint_h)
			{
				ch = getch();
				switch (ch)
				{
					case 'q' :
					case 'Q' :
						loop = 0;
					break;

					case ERR:
					{
						char *msg = NULL;
						do
						{
							msg = utils_log_getmsg(hdhr_device->device->log);
							if (msg)
							{
								win_screen_printw(hdhr_device->screen, msg);
								free(msg);
							}
						} while (msg);
						usleep(1000*500);
						win_screen_update_all(hdhr_device->screen);
					}
					break;

					default:
					break;
				}
			}
		}
		else
		{
			char *msg = NULL;
			while(!sigint_h)
			{
				do
				{
					msg = utils_log_getmsg(hdhr_device->device->log);
					if (msg)
					{
//						win_screen_printw(restream_device->screen, msg);
						printf("%s", msg);
						free(msg);
					}
				} while (msg);
				usleep(1000);
			}
		}


		if (hdhr_device && hdhr_device->device && hdhr_device->device->first_tuner)
			hdhr_destroy(hdhr_device->device->first_tuner);

//		usleep(1000* 2000);
		if (use_curses)
			win_destroy_screen(hdhr_device->screen);
	}
	printf("[HDHR] HDHR app exiting\n");

	return 0;
}
#endif
